using System;
using UnityEngine;
using DanielSig;

namespace DanielSig.UnityExtensions
{
	public static class XVector2
	{
		
		#region REORDER
		#region VECTOR 2
		public static Vector2 XX(this Vector2 v){ return new Vector2(v.x, v.x); }
		public static Vector2 XY(this Vector2 v){ return new Vector2(v.x, v.y); }
		public static Vector2 YX(this Vector2 v){ return new Vector2(v.y, v.x); }
		public static Vector2 YY(this Vector2 v){ return new Vector2(v.y, v.y); }
		#endregion
		#region VECTOR 3
		public static Vector3 XXX(this Vector2 v){ return new Vector3(v.x, v.x, v.x); }
		public static Vector3 XXY(this Vector2 v){ return new Vector3(v.x, v.x, v.y); }
		public static Vector3 XYX(this Vector2 v){ return new Vector3(v.x, v.y, v.x); }
		public static Vector3 XYY(this Vector2 v){ return new Vector3(v.x, v.y, v.y); }
		
		public static Vector3 YXX(this Vector2 v){ return new Vector3(v.y, v.x, v.x); }
		public static Vector3 YXY(this Vector2 v){ return new Vector3(v.y, v.x, v.y); }
		public static Vector3 YYX(this Vector2 v){ return new Vector3(v.y, v.y, v.x); }
		public static Vector3 YYY(this Vector2 v){ return new Vector3(v.y, v.y, v.y); }
		#endregion
		#region VECTOR 4
		public static Vector4 XXXX(this Vector2 v){ return new Vector4(v.x, v.x, v.x, v.x); }
		public static Vector4 XXXY(this Vector2 v){ return new Vector4(v.x, v.x, v.x, v.y); }
		public static Vector4 XXYX(this Vector2 v){ return new Vector4(v.x, v.x, v.y, v.x); }
		public static Vector4 XXYY(this Vector2 v){ return new Vector4(v.x, v.x, v.y, v.y); }
		
		public static Vector4 XYXX(this Vector2 v){ return new Vector4(v.x, v.y, v.x, v.x); }
		public static Vector4 XYXY(this Vector2 v){ return new Vector4(v.x, v.y, v.x, v.y); }
		public static Vector4 XYYX(this Vector2 v){ return new Vector4(v.x, v.y, v.y, v.x); }
		public static Vector4 XYYY(this Vector2 v){ return new Vector4(v.x, v.y, v.y, v.y); }
		
		public static Vector4 YXXX(this Vector2 v){ return new Vector4(v.y, v.x, v.x, v.x); }
		public static Vector4 YXXY(this Vector2 v){ return new Vector4(v.y, v.x, v.x, v.y); }
		public static Vector4 YXYX(this Vector2 v){ return new Vector4(v.y, v.x, v.y, v.x); }
		public static Vector4 YXYY(this Vector2 v){ return new Vector4(v.y, v.x, v.y, v.y); }
		
		public static Vector4 YYXX(this Vector2 v){ return new Vector4(v.y, v.y, v.x, v.x); }
		public static Vector4 YYXY(this Vector2 v){ return new Vector4(v.y, v.y, v.x, v.y); }
		public static Vector4 YYYX(this Vector2 v){ return new Vector4(v.y, v.y, v.y, v.x); }
		public static Vector4 YYYY(this Vector2 v){ return new Vector4(v.y, v.y, v.y, v.y); }
		#endregion
		#endregion
		
		public static String ToStringSharp2(this Vector2 v, int numFractions = 3)
		{
			float power = Mathf.Pow(10F, (float)numFractions);
			float invPower = 1F / power;
			v *= power;
			v.x = ((int)v.x) * invPower;
			v.y = ((int)v.y) * invPower;
			return "(" + v.x + ", " + v.y + ")";
		}
		public static String ToStringSharp2(this Vector2 v)
		{
			return v.ToStringSharp(3);
		}
		
		public static Vector2 Abs(this Vector2 v)
		{
			return new Vector2(v.x > 0 ? v.x : -v.x, v.y > 0 ? v.y : -v.y);
		}
		public static float DistanceTo(this Vector2 v, Vector2 to)
		{
			return (v - to).magnitude;
		}
		public static float DistanceToSqr(this Vector2 v, Vector2 to)
		{
			return (v.x - to.x) * (v.x - to.x)
				 + (v.y - to.y) * (v.y - to.y);
		}
		public static Vector2 Rotate(this Vector2 v, float amount)
		{
			return (Quaternion.Euler(0F, 0F, amount) * v.Join(0F)).XY();
		}
		public static Vector2 Add(this Vector2 v, float x, float y)
		{
			v.x += x;
			v.y += y;
			return v;
		}
		public static Vector2 AddX(this Vector2 v, float value)
		{
			v.x += value;
			return v;
		}
		public static Vector2 AddY(this Vector2 v, float value)
		{
			v.y += value;
			return v;
		}
		public static Vector2 GetScaled(this Vector2 v, Vector2 scalar)
		{
			v.x *= scalar.x;
			v.y *= scalar.y;
			return v;
		}
		public static Vector2 Scale(this Vector2 v, float x, float y)
		{
			v.x *= x;
			v.y *= y;
			return v;
		}
		public static Vector2 ScaleX(this Vector2 v, float scale)
		{
			v.x *= scale;
			return v;
		}
		public static Vector2 ScaleY(this Vector2 v, float scale)
		{
			v.y *= scale;
			return v;
		}
		public static Vector2 MultiplyWith(this Vector2 v, Vector2 vector)
		{
			v.x = v.x * vector.x;
			v.y = v.y * vector.y;
			return v;
		}
		public static Vector2 ClampMin(this Vector2 v, float minX, float minY)
		{
			v.x = v.x.Max(minX);
			v.y = v.y.Max(minY);
			return v;
		}
		public static Vector2 ClampMin(this Vector2 v, Vector2 min)
		{
			return v.ClampMin(min.x, min.y);
		}
		public static Vector2 ClampMax(this Vector2 v, float maxX, float maxY)
		{
			v.x = v.x.Min(maxX);
			v.y = v.y.Min(maxY);
			return v;
		}
		public static Vector2 ClampMax(this Vector2 v, Vector2 max)
		{
			return v.ClampMax(max.x, max.y);
		}
		
		public static Vector2 ConstrainMaxMagnitude(this Vector2 v, float maxMagnitude)
		{
			float length = v.sqrMagnitude;
			if(length > maxMagnitude * maxMagnitude)
			{
				return v * ((maxMagnitude * maxMagnitude) / length);
			}
			return v;
		}
		public static Vector2 ConstrainMinMagnitude(this Vector2 v, float minMagnitude)
		{
			float length = v.sqrMagnitude;
			if(length < minMagnitude * minMagnitude)
			{
				return v * ((minMagnitude * minMagnitude) / length);
			}
			return v;
		}
		public static Vector2 ConstrainMagnitude(this Vector2 v, float maxMagnitude, float minMagnitude)
		{
			float length = v.sqrMagnitude;
			if(length > maxMagnitude * maxMagnitude)
			{
				return v * ((maxMagnitude * maxMagnitude) / length);
			} else if(length < minMagnitude * minMagnitude)
			{
				return v * ((minMagnitude * minMagnitude) / length);
			}
			return v;
		}
		public static Vector2 ConstrainMaxMagnitudeSqr(this Vector2 v, float maxMagnitude)
		{
			float length = v.sqrMagnitude;
			if(length > maxMagnitude)
			{
				return v * (maxMagnitude / length);
			}
			return v;
		}
		public static Vector2 ConstrainMinMagnitudeSqr(this Vector2 v, float minMagnitude)
		{
			float length = v.sqrMagnitude;
			if(length < minMagnitude)
			{
				return v * (minMagnitude / length);
			}
			return v;
		}
		public static Vector2 ConstrainMagnitudeSqr(this Vector2 v, float maxMagnitude, float minMagnitude)
		{
			float length = v.sqrMagnitude;
			if(length > maxMagnitude)
			{
				return v * (maxMagnitude / length);
			} else if(length < minMagnitude)
			{
				return v * (minMagnitude / length);
			}
			return v;
		}
	}
}

